﻿using System;
using System.Collections.Generic;
using Framework.Specifications;
using Framework.UnitOfWork;
using System.Linq.Expressions;
using System.Linq;

namespace Framework.Repositories
{
    /// <summary>
    /// Represents the base class for repositories.
    /// </summary>
    /// <typeparam name="TAggregateRoot">The type of the aggregate root.</typeparam>
    public abstract class Repository<TAggregateRoot> : IRepository<TAggregateRoot>
        where TAggregateRoot : class, IAggregateRoot, new()
    {
        #region Private Fields
        IUnitOfWork _unitOfWork;
        #endregion

        /// <summary>
        /// Gets the instance of the Unit of work on which the repository was attached.
        /// </summary>
        public IUnitOfWork UnitOfWork
        {
            get { return this._unitOfWork; }
        }

        #region Construct
        /// <summary>
        /// Initializes a new instance of <c>Repository&lt;TAggregateRoot&gt;</c> class.
        /// </summary>
        /// <param name="context">The repository context being used by the repository.</param>
        public Repository(IUnitOfWork unitOfWork)
        {
            this._unitOfWork = unitOfWork;
        }
        #endregion

        #region Protected Methods
        /// <summary>
        /// Adds an entity to the repository.
        /// </summary>
        /// <param name="entity">The entity object to be added.</param>
        protected abstract void DoAdd(IQueryable<TAggregateRoot> entities);
        protected abstract void DoAdd(TAggregateRoot entity);
        /// <summary>
        /// Gets the entity instance from repository by a given key.
        /// </summary>
        /// <param name="key">The key of the entity.</param>
        /// <returns>The instance of the entity.</returns>
        protected abstract TAggregateRoot DoGetByKey(params object[] keyValues);
        /// <summary>
        /// Gets all the aggregate roots from repository.
        /// </summary>
        /// <returns>All the aggregate roots got from the repository.</returns>
        protected virtual IQueryable<TAggregateRoot> DoGetAll(Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return DoGetAll(new AllSpecification<TAggregateRoot>(), null, Storage.SortOrder.Unspecified, includePath);
        }
        /// <summary>
        /// Gets all the aggregate roots from repository, sorting by using the provided sort predicate
        /// and the specified sort order.
        /// </summary>
        /// <param name="sortPredicate">The sort predicate which is used for sorting.</param>
        /// <param name="sortOrder">The <see cref="Framework.Enumerations.SortOrder"/> enum which specifies the sort order.</param>
        /// <returns>All the aggregate roots got from the repository, with the aggregate roots being sorted by
        /// using the provided sort predicate and the sort order.</returns>
        protected virtual IQueryable<TAggregateRoot> DoGetAll(Expression<Func<TAggregateRoot, dynamic>> sortPredicate, Storage.SortOrder sortOrder, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return DoGetAll(new AllSpecification<TAggregateRoot>(), sortPredicate, sortOrder, includePath);
        }
        /// <summary>
        /// Gets all the aggregate roots that match the given specification.
        /// </summary>
        /// <param name="specification">The specification with which the aggregate roots should match.</param>
        /// <returns>All the aggregate roots that match the given specification.</returns>
        protected virtual IQueryable<TAggregateRoot> DoGetAll(ISpecification<TAggregateRoot> specification, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return DoGetAll(specification, null, Storage.SortOrder.Unspecified, includePath);
        }
        /// <summary>
        /// Gets all the aggregate roots that match the given specification, and sorts the aggregate roots
        /// by using the provided sort predicate and the specified sort order.
        /// </summary>
        /// <param name="specification">The specification with which the aggregate roots should match.</param>
        /// <param name="sortPredicate">The sort predicate which is used for sorting.</param>
        /// <param name="sortOrder">The <see cref="Framework.Enumerations.SortOrder"/> enum which specifies the sort order.</param>
        /// <returns>All the aggregate roots that match the given specification and were sorted by using the given sort predicate and the sort order.</returns>
        protected abstract IQueryable<TAggregateRoot> DoGetAll(ISpecification<TAggregateRoot> specification, Expression<Func<TAggregateRoot, dynamic>> sortPredicate, Storage.SortOrder sortOrder, Expression<Func<TAggregateRoot, dynamic>> includePath = null);
        /// <summary>
        /// Finds all the aggregate roots from repository.
        /// </summary>
        /// <returns>All the aggregate roots got from the repository.</returns>
        protected virtual IQueryable<TAggregateRoot> DoFindAll(Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return DoFindAll(null, null, Storage.SortOrder.Unspecified, includePath);
        }
        /// <summary>
        /// Finds all the aggregate roots from repository, sorting by using the provided sort predicate
        /// and the specified sort order.
        /// </summary>
        /// <param name="sortPredicate">The sort predicate which is used for sorting.</param>
        /// <param name="sortOrder">The <see cref="Framework.Enumerations.SortOrder"/> enum which specifies the sort order.</param>
        /// <returns>All the aggregate roots got from the repository, with the aggregate roots being sorted by
        /// using the provided sort predicate and the sort order.</returns>
        protected virtual IQueryable<TAggregateRoot> DoFindAll(Expression<Func<TAggregateRoot, dynamic>> sortPredicate, Storage.SortOrder sortOrder, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return DoFindAll(new AllSpecification<TAggregateRoot>(), sortPredicate, sortOrder, includePath);
        }
        /// <summary>
        /// Finds all the aggregate roots that match the given specification.
        /// </summary>
        /// <param name="specification">The specification with which the aggregate roots should match.</param>
        /// <returns>All the aggregate roots that match the given specification.</returns>
        protected virtual IQueryable<TAggregateRoot> DoFindAll(ISpecification<TAggregateRoot> specification, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return DoFindAll(specification, null, Storage.SortOrder.Unspecified, includePath);
        }
        /// <summary>
        /// Finds all the aggregate roots that match the given specification, and sorts the aggregate roots
        /// by using the provided sort predicate and the specified sort order.
        /// </summary>
        /// <param name="specification">The specification with which the aggregate roots should match.</param>
        /// <param name="sortPredicate">The sort predicate which is used for sorting.</param>
        /// <param name="sortOrder">The <see cref="Framework.Enumerations.SortOrder"/> enum which specifies the sort order.</param>
        /// <returns>All the aggregate roots that match the given specification and were sorted by using the given sort predicate and the sort order.</returns>
        protected abstract IQueryable<TAggregateRoot> DoFindAll(ISpecification<TAggregateRoot> specification, Expression<Func<TAggregateRoot, dynamic>> sortPredicate, Storage.SortOrder sortOrder, Expression<Func<TAggregateRoot, dynamic>> includePath = null);
        /// <summary>
        /// Gets a single entity instance from repository by using the given specification.
        /// </summary>
        /// <param name="specification">The specification.</param>
        /// <returns>The entity instance.</returns>
        protected abstract TAggregateRoot DoGet(ISpecification<TAggregateRoot> specification, Expression<Func<TAggregateRoot, dynamic>> includePath = null);
        /// <summary>
        /// Finds a single aggregate root that matches the given specification.
        /// </summary>
        /// <param name="specification">The specification with which the aggregate root should match.</param>
        /// <returns>The instance of the aggregate root.</returns>
        protected abstract TAggregateRoot DoFind(ISpecification<TAggregateRoot> specification, Expression<Func<TAggregateRoot, dynamic>> path = null);
        /// <summary>
        /// Checkes whether the aggregate root which matches the given specification exists.
        /// </summary>
        /// <param name="specification">The specification with which the aggregate root should match.</param>
        /// <returns>True if the aggregate root exists, otherwise false.</returns>
        protected abstract bool DoExists(ISpecification<TAggregateRoot> specification);
        /// <summary>
        /// Removes the entity from the repository.
        /// </summary>
        /// <param name="entity">The entity to be removed.</param>
        protected abstract void DoRemove(TAggregateRoot entity);
        /// <summary>
        /// Updates the entity in the repository.
        /// </summary>
        /// <param name="entity">The entity to be updated.</param>
        protected abstract void DoUpdate(TAggregateRoot entity);
        protected abstract IQueryable<TAggregateRoot> DoPageFind(int pageIndex, int pageSize, System.Linq.Expressions.Expression<Func<TAggregateRoot, dynamic>> orderByExpression, ISpecification<TAggregateRoot> specification, bool ascending, Expression<Func<TAggregateRoot, dynamic>> includePath = null);

        protected abstract IQueryable<TAggregateRoot> DoPageFind(int pageIndex, int pageSize, System.Linq.Expressions.Expression<Func<TAggregateRoot, dynamic>> orderByExpression, ISpecification<TAggregateRoot> specification, bool ascending, ref long totalCount, Expression<Func<TAggregateRoot, dynamic>> includePath = null);

        protected abstract IQueryable<TAggregateRoot> DoPageFind(int pageIndex, int pageSize, string[] orderByFileds, ISpecification<TAggregateRoot> specification, bool ascending, ref long totalCount, Expression<Func<TAggregateRoot, dynamic>> includePath = null);

        protected abstract IQueryable<TAggregateRoot> DoPageFind(int pageIndex, int pageSize, string[] orderByFileds, ISpecification<TAggregateRoot> specification, bool ascending, Expression<Func<TAggregateRoot, dynamic>> includePath = null);
    
        #endregion

        #region IRepository<TEntity> Members
 
        /// <summary>
        /// Adds an entity to the repository.
        /// </summary>
        /// <param name="entity">The entity object to be added.</param>
        /// <exception cref="Framework.Repositories.RepositoryException">Occurs when failed to perform the specific operation.</exception>
        public void Add(IQueryable<TAggregateRoot> entities)
        {
            this.DoAdd(entities);
        }
        
        public void Add(TAggregateRoot entity)
        {
            this.DoAdd(entity);
        }
        /// <summary>
        /// Gets the entity instance from repository by a given key.
        /// </summary>
        /// <param name="key">The key of the entity.</param>
        /// <returns>The instance of the entity.</returns>
        /// <exception cref="Framework.Repositories.RepositoryException">Occurs when failed to perform the specific operation.</exception>
        public TAggregateRoot GetByKey(params object[] keyValues)
        {
            return this.DoGetByKey(keyValues);
        }
        /// <summary>
        /// Gets all the aggregate roots from repository.
        /// </summary>
        /// <returns>All the aggregate roots got from the repository.</returns>
        /// <exception cref="Framework.Repositories.RepositoryException">Occurs when failed to perform the specific operation.</exception>
        public IQueryable<TAggregateRoot> GetAll(Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
           return this.DoGetAll(includePath);
        }
        /// <summary>
        /// Gets all the aggregate roots from repository, sorting by using the provided sort predicate
        /// and the specified sort order.
        /// </summary>
        /// <param name="sortPredicate">The sort predicate which is used for sorting.</param>
        /// <param name="sortOrder">The <see cref="Framework.Enumerations.SortOrder"/> enum which specifies the sort order.</param>
        /// <returns>All the aggregate roots got from the repository, with the aggregate roots being sorted by
        /// using the provided sort predicate and the sort order.</returns>
        /// <exception cref="Framework.Repositories.RepositoryException">Occurs when failed to perform the specific operation.</exception>
        public IQueryable<TAggregateRoot> GetAll(Expression<Func<TAggregateRoot, dynamic>> sortPredicate, Storage.SortOrder sortOrder, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return this.DoGetAll(sortPredicate, sortOrder, includePath);
        }
        /// <summary>
        /// Gets all the aggregate roots that match the given specification.
        /// </summary>
        /// <param name="specification">The specification with which the aggregate roots should match.</param>
        /// <returns>All the aggregate roots that match the given specification.</returns>
        /// <exception cref="Framework.Repositories.RepositoryException">Occurs when failed to perform the specific operation.</exception>
        public IQueryable<TAggregateRoot> GetAll(ISpecification<TAggregateRoot> specification, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return this.DoGetAll(specification, includePath);
        }
        /// <summary>
        /// Gets all the aggregate roots that match the given specification, and sorts the aggregate roots
        /// by using the provided sort predicate and the specified sort order.
        /// </summary>
        /// <param name="specification">The specification with which the aggregate roots should match.</param>
        /// <param name="sortPredicate">The sort predicate which is used for sorting.</param>
        /// <param name="sortOrder">The <see cref="Framework.Enumerations.SortOrder"/> enum which specifies the sort order.</param>
        /// <returns>All the aggregate roots that match the given specification and were sorted by using the given sort predicate and the sort order.</returns>
        /// <exception cref="Framework.Repositories.RepositoryException">Occurs when failed to perform the specific operation.</exception>
        public IQueryable<TAggregateRoot> GetAll(ISpecification<TAggregateRoot> specification, Expression<Func<TAggregateRoot, dynamic>> sortPredicate, Storage.SortOrder sortOrder, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return this.DoGetAll(specification, sortPredicate, sortOrder, includePath);
        }
        /// <summary>
        /// Removes the entity from the repository.
        /// </summary>
        /// <param name="entity">The entity to be removed.</param>
        /// <exception cref="Framework.Repositories.RepositoryException">Occurs when failed to perform the specific operation.</exception>
        public void Remove(TAggregateRoot entity)
        {
            this.DoRemove(entity);
        }

        public void Remove(IEnumerable<TAggregateRoot> entities)
        {
            foreach (var entity in entities)
            {
                this.DoRemove(entity);
            }
        }
        /// <summary>
        /// Updates the entity in the repository.
        /// </summary>
        /// <param name="entity">The entity to be updated.</param>
        /// <exception cref="Framework.Repositories.RepositoryException">Occurs when failed to perform the specific operation.</exception>
        public void Update(TAggregateRoot entity)
        {
            this.DoUpdate(entity);
        }
        /// <summary>
        /// Gets a single entity instance from repository by using the given specification.
        /// </summary>
        /// <param name="specification">The specification.</param>
        /// <returns>The entity instance.</returns>
        /// <exception cref="Framework.Repositories.RepositoryException">Occurs when failed to perform the specific operation.</exception>
        public TAggregateRoot Get(ISpecification<TAggregateRoot> specification, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return this.DoGet(specification, includePath);
        }
        /// <summary>
        /// Finds all the aggregate roots from repository.
        /// </summary>
        /// <returns>All the aggregate roots got from the repository.</returns>
        /// <exception cref="Framework.Repositories.RepositoryException">Occurs when failed to perform the specific operation.</exception>
        public IQueryable<TAggregateRoot> FindAll(Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return this.DoFindAll(includePath);
        }
        /// <summary>
        /// Finds all the aggregate roots from repository, sorting by using the provided sort predicate
        /// and the specified sort order.
        /// </summary>
        /// <param name="sortPredicate">The sort predicate which is used for sorting.</param>
        /// <param name="sortOrder">The <see cref="Framework.Enumerations.SortOrder"/> enum which specifies the sort order.</param>
        /// <returns>All the aggregate roots got from the repository, with the aggregate roots being sorted by
        /// using the provided sort predicate and the sort order.</returns>
        /// <exception cref="Framework.Repositories.RepositoryException">Occurs when failed to perform the specific operation.</exception>
        public IQueryable<TAggregateRoot> FindAll(Expression<Func<TAggregateRoot, dynamic>> sortPredicate, Storage.SortOrder sortOrder, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return this.DoFindAll(sortPredicate, sortOrder, includePath);
        }
        /// <summary>
        /// Finds all the aggregate roots that match the given specification.
        /// </summary>
        /// <param name="specification">The specification with which the aggregate roots should match.</param>
        /// <returns>All the aggregate roots that match the given specification.</returns>
        /// <exception cref="Framework.Repositories.RepositoryException">Occurs when failed to perform the specific operation.</exception>
        public IQueryable<TAggregateRoot> FindAll(ISpecification<TAggregateRoot> specification, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return this.DoFindAll(specification, includePath);
        }
        /// <summary>
        /// Finds all the aggregate roots that match the given specification, and sorts the aggregate roots
        /// by using the provided sort predicate and the specified sort order.
        /// </summary>
        /// <param name="specification">The specification with which the aggregate roots should match.</param>
        /// <param name="sortPredicate">The sort predicate which is used for sorting.</param>
        /// <param name="sortOrder">The <see cref="Framework.Enumerations.SortOrder"/> enum which specifies the sort order.</param>
        /// <returns>All the aggregate roots that match the given specification and were sorted by using the given sort predicate and the sort order.</returns>
        /// <exception cref="Framework.Repositories.RepositoryException">Occurs when failed to perform the specific operation.</exception>
        public IQueryable<TAggregateRoot> FindAll(ISpecification<TAggregateRoot> specification, Expression<Func<TAggregateRoot, dynamic>> sortPredicate, Storage.SortOrder sortOrder, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return this.DoFindAll(specification, sortPredicate, sortOrder, includePath);
        }
        /// <summary>
        /// Finds a single aggregate root that matches the given specification.
        /// </summary>
        /// <param name="specification">The specification with which the aggregate root should match.</param>
        /// <returns>The instance of the aggregate root.</returns>
        /// <exception cref="Framework.Repositories.RepositoryException">Occurs when failed to perform the specific operation.</exception>
        public TAggregateRoot Find(ISpecification<TAggregateRoot> specification, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return this.DoFind(specification, includePath);
        }
        /// <summary>
        /// Checkes whether the aggregate root which matches the given specification exists.
        /// </summary>
        /// <param name="specification">The specification with which the aggregate root should match.</param>
        /// <returns>True if the aggregate root exists, otherwise false.</returns>
        /// <exception cref="Framework.Repositories.RepositoryException">Occurs when failed to perform the specific operation.</exception>
        public bool Exists(ISpecification<TAggregateRoot> specification)
        {
            return this.DoExists(specification);
        }

        #endregion

        #region IRepository<TAggregateRoot> Members


        public TAggregateRoot Find(System.Linq.Expressions.Expression<Func<TAggregateRoot, bool>> specification, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return DoFind(Specification<TAggregateRoot>.Eval(specification), includePath);
        }

        #endregion

        #region IRepository<TAggregateRoot> Members


        public IQueryable<TAggregateRoot> GetAll(System.Linq.Expressions.Expression<Func<TAggregateRoot, bool>> specification, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return DoGetAll(Specification<TAggregateRoot>.Eval(specification), includePath);
        }

        public IQueryable<TAggregateRoot> GetAll(System.Linq.Expressions.Expression<Func<TAggregateRoot, bool>> specification, Expression<Func<TAggregateRoot, dynamic>> sortPredicate, Storage.SortOrder sortOrder, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return DoGetAll(Specification<TAggregateRoot>.Eval(specification), sortPredicate, sortOrder, includePath);
        }

        public TAggregateRoot Get(Expression<Func<TAggregateRoot, bool>> specification, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return DoGet(Specification<TAggregateRoot>.Eval(specification), includePath);
        }

        public IQueryable<TAggregateRoot> FindAll(System.Linq.Expressions.Expression<Func<TAggregateRoot, bool>> specification, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return DoFindAll(Specification<TAggregateRoot>.Eval(specification), includePath);
        }

        public IQueryable<TAggregateRoot> FindAll(System.Linq.Expressions.Expression<Func<TAggregateRoot, bool>> specification, Expression<Func<TAggregateRoot, dynamic>> sortPredicate, Storage.SortOrder sortOrder, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return DoFindAll(Specification<TAggregateRoot>.Eval(specification), sortPredicate, sortOrder, includePath);
        }

        public bool Exists(System.Linq.Expressions.Expression<Func<TAggregateRoot, bool>> specification)
        {
            return DoExists(Specification<TAggregateRoot>.Eval(specification));
        }

        public IQueryable<TAggregateRoot> PageFind(int pageIndex, int pageSize, System.Linq.Expressions.Expression<Func<TAggregateRoot, dynamic>> orderByExpression, ISpecification<TAggregateRoot> specification, bool ascending, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return this.DoPageFind(pageIndex, pageSize, orderByExpression, specification, ascending, includePath);
        }

        public IQueryable<TAggregateRoot> PageFind(int pageIndex, int pageSize, System.Linq.Expressions.Expression<Func<TAggregateRoot, dynamic>> orderByExpression, ISpecification<TAggregateRoot> specification, bool ascending, ref long totalCount, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return this.DoPageFind(pageIndex, pageSize, orderByExpression, specification, ascending, ref totalCount, includePath);
        }


        public IQueryable<TAggregateRoot> PageFind(int pageIndex, int pageSize, System.Linq.Expressions.Expression<Func<TAggregateRoot, dynamic>> orderByExpression, System.Linq.Expressions.Expression<Func<TAggregateRoot, bool>> specification, bool ascending, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return DoPageFind(pageIndex, pageSize, orderByExpression, Specification<TAggregateRoot>.Eval(specification), ascending, includePath);
        }

        public IQueryable<TAggregateRoot> PageFind(int pageIndex, int pageSize, System.Linq.Expressions.Expression<Func<TAggregateRoot, dynamic>> orderByExpression, System.Linq.Expressions.Expression<Func<TAggregateRoot, bool>> specification, bool ascending, ref long totalCount, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return DoPageFind(pageIndex, pageSize, orderByExpression, Specification<TAggregateRoot>.Eval(specification), ascending, ref totalCount, includePath);

        }


        public IQueryable<TAggregateRoot> PageFind(int pageIndex, int pageSize, string[] orderByFileds, System.Linq.Expressions.Expression<Func<TAggregateRoot, bool>> specification, bool ascending, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return DoPageFind(pageIndex, pageSize, orderByFileds, Specification<TAggregateRoot>.Eval(specification), ascending, includePath);
        }

        public IQueryable<TAggregateRoot> PageFind(int pageIndex, int pageSize, string[] orderByFileds, System.Linq.Expressions.Expression<Func<TAggregateRoot, bool>> specification, bool ascending, ref long totalCount, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return DoPageFind(pageIndex, pageSize, orderByFileds, Specification<TAggregateRoot>.Eval(specification), ascending, ref totalCount, includePath);

        }


        public IQueryable<TAggregateRoot> PageFind(int pageIndex, int pageSize, string[] orderByFileds, ISpecification<TAggregateRoot> specification, bool ascending, ref long totalCount, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return DoPageFind(pageIndex, pageSize, orderByFileds, specification, ascending, ref totalCount, includePath);
        }

        public IQueryable<TAggregateRoot> PageFind(int pageIndex, int pageSize, string[] orderByFileds, ISpecification<TAggregateRoot> specification, bool ascending, Expression<Func<TAggregateRoot, dynamic>> includePath = null)
        {
            return DoPageFind(pageIndex, pageSize, orderByFileds, specification, ascending, includePath);
        }


        #endregion

        #region IRepository<TAggregateRoot> Members

        public long Count(Expression<Func<TAggregateRoot, bool>> specification)
        {
            return DoCount(specification);
        }

        public long Count(ISpecification<TAggregateRoot> specification)
        {
            return DoCount(specification);
        }


        protected abstract long DoCount(ISpecification<TAggregateRoot> specification);
        protected abstract long DoCount(Expression<Func<TAggregateRoot, bool>> specification);

        #endregion
    }
}
